home *** CD-ROM | disk | FTP | other *** search
- // SpaceView.m
- //
- // This class implements the flying starfield screen saver view.
- //
- // You may freely copy, distribute, and reuse the code in this example.
- // NeXT disclaims any warranty of any kind, expressed or implied, as to its
- // fitness for any particular use.
-
-
- #import "SpaceView.h"
- #import "Thinker.h"
- #import "psfuncts.h"
-
- #import <dpsclient/wraps.h>
- #import <appkit/NXImage.h>
- #import <objc/zone.h>
- #import <mach/mach.h>
- #import <c.h>
- #import <libc.h>
- #import <math.h>
-
- #define PI (3.141592653589)
-
- @implementation SpaceView
-
- //takes theta and distance and stuffs it into x &y for *p
- - convertToXY:(STAR *)p
- {
- p->draw->x = floor(bounds.size.width / 2 + (p->distance * cos(p-> theta)));
- p->draw->y = floor(bounds.size.height / 2 + (p->distance * sin(p-> theta)));
- return self;
- }
-
-
- - oneStep
- {
- int i, count, starsInArray = 0;
- STAR *p;
- NXPoint *t;
-
- if (nstars < NSTARS) [self addStar];
-
- for (i=0; i<nstars; i++)
- {
- p = &stars[i];
- p->distance += p->delta;
- p->delta *= p->ddelta;
-
- [self convertToXY:p];
-
- // only draw the star if it moved > 1 pixel
- if (p->draw->x != p->erase->x ||
- p->draw->y != p->erase->y)
- {
- BOOL mustErase = NO;
- // add star to the erasure array
- b[starsInArray] = *p->erase;
- bc[starsInArray] = p->c;
-
- if (p->distance > p->changepoint[p->changemode])
- {
- (p->c)++; // increment character for next star size
- (p->changemode)++;
- }
-
- // clipping is off, so we must not draw outside view.
- // replace stars that go too far...
- if (p->draw->x < 0 ||
- p->draw->y < 0 ||
- p->draw->x + 7 > bounds.size.width ||
- p->draw->y + 7 > bounds.size.height)
- {
- [self replaceStarAt:i];
- mustErase = YES;
- }
-
- w[starsInArray] = *p->draw;
- wc[starsInArray] = p->c;
-
- if (mustErase || [self allowStars:p]) starsInArray++;
-
- t = p->draw; p->draw = p->erase; p->erase = t;
- }
- }
-
- bc[starsInArray] = wc[starsInArray] = 0; //null terminate string
- if (starsInArray)
- {
- for (i=0; i<(starsInArray-1); i++)
- {
- bOffsets[i].x = b[i+1].x - b[i].x;
- bOffsets[i].y = b[i+1].y - b[i].y;
- wOffsets[i].x = w[i+1].x - w[i].x;
- wOffsets[i].y = w[i+1].y - w[i].y;
- }
- bOffsets[i].x = bOffsets[i].y = wOffsets[i].x = wOffsets[i].y = 0;
-
- count = 0;
- while (count < starsInArray)
- { char tc;
- int j;
- // You get the best performance if you put out all the stars
- // at once. This causes noticable flicker, so I put out
- // 100 of the stars per iteration. This gives reasonable speed
- // and flicker is hardly noticable. Besides, stars
- // _should_ flicker a little...
-
- int t = (starsInArray - count);
- i = (t < STARSPERIT)?t:STARSPERIT;
- j = i + count;
-
- PSsetgray(NX_BLACK);
- tc = bc[j]; bc[j] = 0;
- PSWXYShow(b[count].x, b[count].y, &bc[count],
- (float *)(&bOffsets[count].x), i*2);
- bc[j] = tc;
-
- PSsetgray(NX_WHITE);
- tc = wc[j]; wc[j] = 0;
- PSWXYShow(w[count].x, w[count].y, &wc[count],
- (float *)(&wOffsets[count].x), i*2);
- wc[j] = tc;
-
- count += STARSPERIT;
- }
- }
-
- return self;
- }
-
- // returns yes if the star is outside the avoidance rectangle
- // this is really fast and loose but it works acceptibly well
- // ps I could just use NXIntersectsRect() but I want to avoid
- // trap overhead. Call me paranoid...
- - (BOOL) allowStars:(const STAR *)p
- {
- // just return if voidRect not set
- if ((!voidRect.size.width) ||
- p->draw->x < voidRect.origin.x ||
- p->draw->y < voidRect.origin.y ||
- p->draw->x+7 > voidRect.origin.x+voidRect.size.width ||
- p->draw->y+7 > voidRect.origin.y+voidRect.size.height ||
-
- p->erase->x < voidRect.origin. x ||
- p->erase->y < voidRect.origin. y ||
- p->erase->x+7 > voidRect.origin.x+voidRect.size.width ||
- p->erase->y+7 > voidRect.origin.y+voidRect.size.height) return YES;
-
- return NO;
- }
-
- - initFrame:(const NXRect *)frameRect
- {
- [super initFrame:frameRect];
- [self allocateGState]; // For faster lock/unlockFocus
- [self setClipping:NO]; // even faster...
- [self setRadius];
- loadPSProcedures();
- PSWDefineFont("StarFont");
-
- return self;
- }
-
- - drawSelf:(const NXRect *)rects :(int)rectCount
- {
- // this drawself doesn't really draw the view at all.
- // in fact it just promotes the window to screen depth...
-
- NXRect t = {0,0,1,1};
-
- PSsetrgbcolor(1,0,0);
- NXRectFill(&t); //yucky trick for window depth promotion!
- PSsetgray(NX_BLACK); NXRectFill(&t);
-
- PSselectfont("StarFont", 1.0);
-
- return self;
- }
-
- - sizeTo:(NXCoord)width :(NXCoord)height
- {
- [super sizeTo:width :height];
-
- if (oldSize.width != bounds.size.width ||
- oldSize.height != bounds.size.height)
- {
- oldSize.width = bounds.size.width;
- oldSize.height = bounds.size.height;
- [self setRadius];
- nstars = 0;
- [self display];
- }
-
- return self;
- }
-
- // only call addStar if there is room in the stars array!
- - addStar
- {
- [self replaceStarAt:nstars++];
- return self;
- }
-
- - replaceStarAt:(int)index
- {
- float dist, t;
- int tries = 0;
- STAR *p = &stars[index];
- BOOL inBounds;
-
- p->draw = &p->r1;
- p->erase = &p->r2;
-
-
- do {
- p->theta = randBetween(0,(2*PI));
-
- if (tries++ < 3) p->distance = randBetween(1, radius);
- else p->distance = randBetween(1, p->distance);
-
- inBounds = YES;
- [self convertToXY:p];
-
- if (p->draw->x < 0 || p->draw->y < 0 ||
- p->draw->x + 7 > bounds.size.width ||
- p->draw->y + 7 > bounds.size.height)
- {
- inBounds = NO;
- }
- } while (!inBounds);
-
- p->delta = (0.2);
-
- p->ddelta = randBetween(1.0, 1.1);
-
-
-
- t = randBetween(0, (0.42*radius));
- dist = MAX(20,t);
- p->changepoint[0] = p->distance + 5; // to b
- p->changepoint[1] = p->changepoint[0] - 5 + dist + dist; // to c
-
-
- p->changepoint[2] = p->changepoint[1] + dist; // to d
- p->changepoint[3] = p->changepoint[2] + dist; // to e
- p->changepoint[4] = p->changepoint[3] + dist; // to f
- p->changepoint[5] = 100000; // never change to g
-
- p->changemode = 0;
-
- if ((++toggle) & 1) p->c = 'a';
- else p->c = 'g';
-
- p->r2 = p->r1;
-
- return self;
- }
-
- - setRadius
- {
- float x = bounds.size.width;
- float y = bounds.size.height;
- radius = (sqrt(x*x + y*y))/2;
- return self;
- }
-
- - (const char *)windowTitle
- {
- return "The Final Frontier";
- }
-
- - setVoidRect:(const NXRect *)r
- {
- voidRect = *r;
- return self;
- }
-
- - didLockFocus
- {
- PSselectfont("StarFont", 1.0);
- return self;
- }
-
- - (BOOL)useBufferedWindow
- { return NO;
- }
-
- - inspector:sender
- {
- return [sender spaceInspector];
- }
-
- - (BOOL)ignoreMouseMovement
- { return NO;
- }
-
- - inspectorWillBeRemoved
- { return self; // just a prototype
- }
-
- - inspectorInstalled
- { return self; // just a prototype
- }
-
- @end
-
-
-
- // this class is only used in the inspector, it animates
- // when it draws itself.
-
- @implementation StaticSpaceView
-
- - drawSelf:(const NXRect *)rects :(int)rectCount
- {
- int i;
-
- if (!rects || !rectCount) return self;
-
- PSselectfont("StarFont", 1.0);
-
- PSsetgray(NX_BLACK);
- NXRectFill(rects);
-
- for (i=0; i<20; i++)
- {
- [self oneStep];
- [[self window] flushWindow];
- NXPing();
- }
-
- return self;
- }
-
- - initFrame:(const NXRect *)frameRect
- {
- [super initFrame:frameRect];
-
- while (nstars < NSTARS) [self addStar];
- return self;
- }
-
- - sizeTo:(NXCoord)width :(NXCoord)height
- {
- [super sizeTo:width :height];
-
- nstars = 0;
- while (nstars < NSTARS) [self addStar];
- return self;
- }
-
- @end
-
-
-
-
-
- @implementation View(nonretainedFillMethod)
-
- // I add this method as a category of View to be sure that all
- // my views implement it. I really want to use nonretained windows
- // but they are drawn via drawSelf at all kinds of goofy times. It
- // seems like the kit kind of throws up its hands when it doesn't have
- // a buffer to draw from, so you get a lot more drawSelfs than you need,
- // and sometimes you don't get them when you really want them. I know
- // when I need the background filled in black, so I factor that out of
- // my drawSelf and then drawself only draws things that are already on
- // screen so you don't see it happen. I will only call this method on
- // a nonretained (and full screen) window.
-
- - fillBoundsWithBlack
- {
- if ([self canDraw])
- {
- [self lockFocus];
- PSsetgray(NX_BLACK);
- NXRectFill(&bounds);
- [self unlockFocus];
- }
- return self;
- }
-
- @end
-